package cc.rboot.lock.holder;

import cc.rboot.lock.core.Locker;
import cc.rboot.lock.error.LockTimeoutException;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.locks.ReentrantLock;

@ConditionalOnClass(RedissonClient.class)
@Component
public class LockHolder {

    @Resource
    private RedissonClient redissonClient;

    @Value("${spring.redis.lock.key-prefix}")
    private String keyPrefix;

    /**
     * 锁，按照传入的参数拼接成锁key
     *
     * @param subject
     * @param key
     * @return
     * @throws Exception
     */
    public Locker tryShareLock(String subject, Object key, boolean usePrefix) throws Exception {
        try {
            Locker lock = getShareLock(subject + ":" + key, usePrefix);
            lockIt(lock);
            return lock;
        } catch (Exception ex) {
            throw new LockTimeoutException(ex);
        }
    }

    /**
     * = tryShareLock
     *
     * @param subject
     * @return
     * @throws Exception
     */
    public Locker lock(String subject) throws Exception {
        return lock(subject, "", true);
    }

    /**
     * = tryShareLock
     *
     * @param subject
     * @param key
     * @return
     * @throws Exception
     */
    public Locker lock(String subject, Object key) throws Exception {
        return tryShareLock(subject, key, true);
    }

    /**
     * = tryShareLock
     *
     * @param subject
     * @param key
     * @return
     * @throws Exception
     */
    public Locker lock(String subject, Object key, boolean usePrefix) throws Exception {
        return tryShareLock(subject, key, usePrefix);
    }


    public Locker lock(String subject, boolean usePrefix) throws Exception {
        return lock(subject, "", usePrefix);
    }

    private Locker getShareLock(String key, boolean usePrefix) throws Exception {
        try {

            if(usePrefix) {
                System.out.println("lock => " + keyPrefix + key);
                return new Locker(redissonClient.getLock(keyPrefix + key));
            } else {
                System.out.println("lock => " + key);
                return new Locker(redissonClient.getLock(key));
            }
        } catch (Exception ex) {
            System.out.println("Redis无法连接" + ex);
            return new Locker(new ReentrantLock());
        }
    }

    private void lockIt(Locker lock) throws Exception {
        lock.lock();
    }
}
